package com.winding.plugin.swagger.utils;

import com.google.common.collect.Lists;
import com.thoughtworks.qdox.model.JavaAnnotation;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaMethod;
import com.thoughtworks.qdox.model.JavaParameter;
import com.winding.plugin.swagger.entity.RequestMappingInfo;
import com.winding.plugin.swagger.enums.ControllerObj;
import com.winding.plugin.swagger.enums.RequestMethod;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Optional;

/**
 * <p>TODO
 *
 * @author wind
 * @version 1.0
 * @since 2018/12/5
 */
public class SpringAnnotationUtils {
    private SpringAnnotationUtils() {
    }

    private static List<String> mappingList = Lists.newArrayList("RequestMapping", "GetMapping",
            "PostMapping", "PutMapping", "DeleteMapping", "PatchMapping");
    private static List<String> controllerList = Lists.newArrayList(ControllerObj.Controller.name(), ControllerObj.RestController.name());

    public static RequestMappingInfo getRequestMappingInfo(JavaMethod method) {
        RequestMappingInfo requestMappingInfo = null;
        JavaAnnotation annotation = method.getAnnotations().stream()
                .filter(v -> mappingList.contains(v.getType().getSimpleName())
                )
                .findFirst().get();
        if (annotation != null) {
            requestMappingInfo = new RequestMappingInfo();
            requestMappingInfo.setConsumes(TypeUtil.transList(annotation.getProperty("consumes")));
            requestMappingInfo.setHeaders(TypeUtil.transList(annotation.getProperty("headers")));

            requestMappingInfo.setParams(TypeUtil.transList(annotation.getProperty("params")));
            requestMappingInfo.setPath(TypeUtil.transList(annotation.getProperty("path")));
            requestMappingInfo.setValue(TypeUtil.transList(annotation.getProperty("value")));
            requestMappingInfo.setProduces(TypeUtil.transList(annotation.getProperty("produces")));
            requestMappingInfo.setName(TypeUtil.transString(annotation.getProperty("name")));

            switch (annotation.getType().getSimpleName()) {
                case "RequestMapping":
                    requestMappingInfo.setMethod(TypeUtil.requestMethod(annotation.getProperty("method")));
                    if (requestMappingInfo.getMethod().length == 0) {
                        requestMappingInfo.setMethod(new com.winding.plugin.swagger.enums.RequestMethod[]{RequestMethod.GET, RequestMethod.PATCH,
                                RequestMethod.DELETE, RequestMethod.PUT, RequestMethod.OPTIONS, RequestMethod.POST});
                    }
                    break;
                case "GetMapping":
                    requestMappingInfo.setMethod(new com.winding.plugin.swagger.enums.RequestMethod[]{RequestMethod.GET});
                    break;
                case "PostMapping":
                    requestMappingInfo.setMethod(new com.winding.plugin.swagger.enums.RequestMethod[]{RequestMethod.POST});
                    break;
                case "PutMapping":
                    requestMappingInfo.setMethod(new com.winding.plugin.swagger.enums.RequestMethod[]{RequestMethod.PUT});
                    break;
                case "DeleteMapping":
                    requestMappingInfo.setMethod(new com.winding.plugin.swagger.enums.RequestMethod[]{RequestMethod.DELETE});
                    break;
                case "PatchMapping":
                    requestMappingInfo.setMethod(new com.winding.plugin.swagger.enums.RequestMethod[]{RequestMethod.PATCH});
                    break;
                default:

            }
        }
        return requestMappingInfo;

    }

    public static boolean isRequestBody(JavaParameter parameter) {
        return haveAnnotation(parameter, "RequestBody");
    }

    public static boolean isPathParam(JavaParameter parameter) {
        return haveAnnotation(parameter, "PathVariable");
    }

    public static boolean haveAnnotation(JavaParameter parameter, String name) {
        List<JavaAnnotation> annotations = parameter.getAnnotations();
        if (annotations != null) {
            for (JavaAnnotation annotation : annotations) {
                if (annotation.getType().getSimpleName().equals(name)) {
                    return true;
                }
            }
        }
        return false;

    }

    public static Annotation getFieldAnnotation(Field field, Class annotationTarget) {
        return field.getAnnotation(annotationTarget);
    }

    public static JavaAnnotation getAnnotation(JavaParameter parameter, String annotationTarget) {
        return parameter.getAnnotations().stream().filter(annotation ->
                annotation.getType().getSimpleName().equals(annotationTarget)).findFirst().get();
    }

    public static String getControllerPath(JavaClass javaClass) {
        String path = "";
        Optional<JavaAnnotation> annotation = javaClass.getAnnotations().stream()
                .filter(v -> "RequestMapping".equals(v.getType().getSimpleName())
                )
                .findFirst();
        if (annotation.isPresent()) {
            String[] paths = TypeUtil.transList(annotation.get().getProperty("path"));
            if (paths == null || paths.length <= 0) {
                paths = TypeUtil.transList(annotation.get().getProperty("value"));
            }
            if (paths != null && paths.length > 0) {
                path = paths[0];
            }
        }
        return path;
    }

    public static Boolean isSkip(JavaMethod javaMethod){
        List list=javaMethod.getTagsByName("apiIgnore");
        return list!=null&&list.size()>0;
    }
    public static Boolean isSkip(JavaClass javaClass){
        List list=javaClass.getTagsByName("apiIgnore");
        return list!=null&&list.size()>0;
    }
}
